package yz.cp.back.auth.sign;

import cn.hutool.core.map.MapUtil;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import yz.cp.back.common.res.ApiException;
import yz.cp.back.common.utils.JacksonUtil;
import yz.cp.back.common.utils.SpringUtil;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;

@Slf4j
public class SignRequestUtils {
    public static   AccessAccount accessAccount;
    public static Request createRequest(Object value,boolean isCreate) {
        if (value == null) {
            throw new ApiException("参数缺失");
        }
        String data="";
        if(value instanceof String){
            data=(String)value;
            data = data.trim();
        }
        Request request;
        if (data.startsWith("{")) {
            request = JacksonUtil.from(data, Request.class);
        } else if (data.startsWith("<")) {
            request = JacksonUtil.fromXml(data, Request.class);
        } else {
            if(value instanceof Map){
                request=new QueryStringParser((Map)value).create();
            }else{
                request = new QueryStringParser(data).create();
            }
        }
        if(!isCreate){
            if (StringUtils.isBlank(request.getAppId())) {
                throw new ApiException("参数缺失");
            }
            if (StringUtils.isBlank(request.getTimestamp())) {
                throw new ApiException("参数缺失");
            } else {
                ValidTimeUtils.isValid(request.getTimestamp());
            }
            if (StringUtils.isBlank(request.getNonceStr())) {
                throw new ApiException("参数缺失");
            }else {
                ValidTimeUtils.isValidNonceStr(request.getAppId(),request.getNonceStr());
            }
            if (StringUtils.isBlank(request.getSign())) {
                throw new ApiException("参数缺失");
            }
        }
        if (StringUtils.isBlank(request.getFormat())) {
            request.setFormat("json");
        }
        if (StringUtils.isBlank(request.getSignType())) {
            request.setSignType("md5");
        }
        if (StringUtils.isBlank(request.getV())) {
            request.setV("1.0");
        }
        request.join();
        return request;
    }


    public static boolean valid(Object data) {
        Request request = createRequest(data,false);
        String appSecret =  SpringUtil.getBean(AccessAccount.class).getAppSecret(request.getAppId());
        return StringUtils.equalsIgnoreCase(request.getSign(), EncodeUtils.sign(appSecret, request));
    }

    public static String createSign(String appSecret,Object data){
        Request request = createRequest(data,true);
        return createSign(appSecret,request);
    }

    public static String createSign(String appSecret,Request request){
        return EncodeUtils.sign(appSecret, request);
    }
    public static  AccessAccount getAccessAccount(){
        if(accessAccount==null){
            try {
                accessAccount = SpringUtil.getBean(AccessAccount.class);
            } catch (Exception e) {
                throw new ApiException("缺少获取密钥函数");
            }
        }
        return accessAccount;
    }
    @SneakyThrows
    public static boolean valid(HttpServletRequest httpServletRequest) {
        Request request = createRequest(getRequestQuery(httpServletRequest),false);
        String appSecret = getAccessAccount().getAppSecret(request.getAppId());
        String validSign= createSign(appSecret,request);
        log.info("validSign:{}",validSign);
        log.info("sign:{}",request.getSign());
        return StringUtils.equalsIgnoreCase(request.getSign(),validSign);
    }

    @SneakyThrows
    public static Object getRequestQuery(HttpServletRequest request) {
        if (request.getMethod().equals(HttpMethod.GET.name())) {
            return request.getQueryString();
        } else {// POST
            if(request.getContentType()!=null){
                if(MediaType.MULTIPART_FORM_DATA.includes(MediaType.parseMediaType(request.getContentType()))||
                        MediaType.APPLICATION_FORM_URLENCODED.includes(MediaType.parseMediaType(request.getContentType()))){
                    Map<String,String> map= ServletUtil.getParamMap(request);
                    return MapUtil.join(map,"&","=");
                }else {
                    return getRequestPostBytes(request);
                }
            }
            return getRequestPostBytes(request);
        }
    }



    /***
     * Get request query string, form method : post
     *
     * @param request
     * @return byte[]
     * @throws IOException
     */
    @SneakyThrows
    public static String getRequestPostBytes(HttpServletRequest request) {
        return IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
    }
}
